//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// Use of this sample source code is subject to the terms of the Microsoft
// license agreement under which you licensed this sample source code. If
// you did not accept the terms of the license agreement, you are not
// authorized to use this sample source code. For the terms of the license,
// please see the license agreement between you and Microsoft or, if applicable,
// see the LICENSE.RTF on your install media or the root of your tools installation.
// THE SAMPLE SOURCE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES OR INDEMNITIES.
//
//////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2003 Intrinsyc Europe Ltd.
//////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2004 Siemens AG
//
// Version: 1.1.2.5
// Date:    11. Jan. 2006
//////////////////////////////////////////////////////////////////////////////


#include "precomp.h"


//////////////////////////////////////////////////////////////////////////////
//
// Internal parsing function.
//
// Return:
//  TRUE or FALSE depending on the success of the operation.
//
//////////////////////////////////////////////////////////////////////////////
BOOL CSimToolkitHandling::ParseRefresh(LPCSTR szRsp, void*& pBlob, UINT& cbBlob) {
UINT  nDetails;

  // Parse "<details>"
  if (!ParseUInt(szRsp, FALSE, nDetails, szRsp)  ||
      !ParseRspPostfix(szRsp, szRsp)) {
    return FALSE;
  }

  // NOTE: Some refresh variants require a file list but the module doesn't send one.
  //       So we must adapt cmd details so that no file list is required.
  if ((nDetails == 1) || (nDetails == 2)) {
    nDetails = 0;
  }

  // Fill out the start of the SAT command and the refresh mode
  sprintf(m_szCmdBuffer, "D00081030101%0.2X82028182", nDetails);

  AddSATCmdLength(m_szCmdBuffer);

  if (nDetails == 4) {
    // In case of a full SIM reset the module doesn't require any response
    m_fNoResponse = TRUE;
  }

  // Notify the SIM manager of the SAT command
  return HandleBlob(RIL_NOTIFY_SIMTOOLKITEVENT, pBlob, cbBlob, m_szCmdBuffer);
}

//////////////////////////////////////////////////////////////////////////////
//
// Internal parsing function.
//
// Return:
//  TRUE or FALSE depending on the success of the operation.
//
//////////////////////////////////////////////////////////////////////////////
BOOL CSimToolkitHandling::ParseSetupCall(LPCSTR szRspIn, void*& pBlob, UINT& cbBlob, BOOL fUseGSM) {
UINT    nDetails, nConfIconQualifier, nConfIcon, nSetupIconQualifier, nSetupIcon;
char*   pConfirmation;
char*   pSetup;
char    szConfirmation[MAX_ATCMD_LEN], szNumber[MAX_ATCMD_LEN], szSetup[MAX_ATCMD_LEN];
LPCSTR  szRsp = szRspIn;

  // Prepare text fields
  SIMTK_PREPARE_TEXT(szConfirmation, pConfirmation, SIMTK_TXT_ALPHA);
  SIMTK_PREPARE_TEXT(szSetup, pSetup, SIMTK_TXT_ALPHA);

  // Parse "<details>,<confirmation text>,<called number>,<call setup text>,<conf icon qual>,<conf icon>,<call setup icon qual>,<call setup icon>"
  if (!ParseUInt(szRsp, FALSE, nDetails, szRsp)                 ||
      !ParseRspParamSeparator(szRsp, szRsp)                     ||
      !ParseString(szRsp, pConfirmation, MAX_ATCMD_LEN, szRsp)  ||
      !ParseRspParamSeparator(szRsp, szRsp)                     ||
      !ParseString(szRsp, szNumber, MAX_ATCMD_LEN, szRsp)       ||
      !ParseRspParamSeparator(szRsp, szRsp)                     ||
      !ParseString(szRsp, pSetup, MAX_ATCMD_LEN, szRsp)         ||
      !ParseRspParamSeparator(szRsp, szRsp)                     ||
      !ParseUInt(szRsp, FALSE, nConfIconQualifier, szRsp)       ||
      !ParseRspParamSeparator(szRsp, szRsp)                     ||
      !ParseUInt(szRsp, FALSE, nConfIcon, szRsp)                ||
      !ParseRspParamSeparator(szRsp, szRsp)                     ||
      !ParseUInt(szRsp, FALSE, nSetupIconQualifier, szRsp)      ||
      !ParseRspParamSeparator(szRsp, szRsp)                     ||
      !ParseUInt(szRsp, FALSE, nSetupIcon, szRsp)               ||
      !ParseRspPostfix(szRsp, szRsp)) {
    return FALSE;
  }

  UpdateAlphaField(szConfirmation, fUseGSM);
  UpdateAlphaField(szSetup, fUseGSM);
  ConvertSATAddress(szNumber);

  // Fill out the SAT command
  sprintf(m_szCmdBuffer, "D00081030110%0.2X82028183%s06%0.2XFF%s1E02%0.2X%0.2X%s1E02%0.2X%0.2X",
          nDetails, szConfirmation, (strlen(szNumber)/2)+1, szNumber, nConfIconQualifier, nConfIcon, szSetup, nSetupIconQualifier, nSetupIcon);

  if (!AddSATCmdLength(m_szCmdBuffer)) {
    if (fUseGSM) { return FALSE; }
    return ParseSetupCall(szRspIn, pBlob, cbBlob, TRUE);
  }

  // Notify the SIM manager of the SAT command
  return HandleBlob(RIL_NOTIFY_SIMTOOLKITCMD, pBlob, cbBlob, m_szCmdBuffer);
}

//////////////////////////////////////////////////////////////////////////////
//
// Internal parsing function.
//
// Return:
//  TRUE or FALSE depending on the success of the operation.
//
//////////////////////////////////////////////////////////////////////////////
BOOL CSimToolkitHandling::ParseSendSS(LPCSTR szRspIn, void*& pBlob, UINT& cbBlob, BOOL fUseGSM) {
UINT    nDetails, nIconQualifier, nIcon;
char*   pText;
char    szText[MAX_ATCMD_LEN];
LPCSTR  szRsp = szRspIn;

  // Prepare text field
  SIMTK_PREPARE_TEXT(szText, pText, SIMTK_TXT_ALPHA);

  // Parse "<details>,<text>,<icon qual>,<icon>"
  if (!ParseUInt(szRsp, FALSE, nDetails, szRsp)         ||
      !ParseRspParamSeparator(szRsp, szRsp)             ||
      !ParseString(szRsp, pText, MAX_ATCMD_LEN, szRsp)  ||
      !ParseRspParamSeparator(szRsp, szRsp)             ||
      !ParseUInt(szRsp, FALSE, nIconQualifier, szRsp)   ||
      !ParseRspParamSeparator(szRsp, szRsp)             ||
      !ParseUInt(szRsp, FALSE, nIcon, szRsp)            ||
      !ParseRspPostfix(szRsp, szRsp)) {
    return FALSE;
  }

  UpdateAlphaField(szText, fUseGSM);

  // Fill out the SAT command
  sprintf(m_szCmdBuffer, "D00081030111%0.2X82028183%s0901FF1E02%0.2X%0.2X", nDetails, szText, nIconQualifier, nIcon);

  if (!AddSATCmdLength(m_szCmdBuffer)) {
    if (fUseGSM) { return FALSE; }
    return ParseSendSS(szRspIn, pBlob, cbBlob, TRUE);
  }

  // Notify the SIM manager of the SAT command
  return HandleBlob(RIL_NOTIFY_SIMTOOLKITCMD, pBlob, cbBlob, m_szCmdBuffer);
}

//////////////////////////////////////////////////////////////////////////////
//
// Internal parsing function.
//
// Return:
//  TRUE or FALSE depending on the success of the operation.
//
//////////////////////////////////////////////////////////////////////////////
BOOL CSimToolkitHandling::ParseSendUSSD(LPCSTR szRspIn, void*& pBlob, UINT& cbBlob, BOOL fUseGSM) {
UINT    nDetails, nIconQualifier, nIcon;
char    *pText;
char    szText[MAX_ATCMD_LEN];
LPCSTR  szRsp = szRspIn;

  // Prepare text field
  SIMTK_PREPARE_TEXT(szText, pText, SIMTK_TXT_ALPHA);

  // Parse "<details>,<text>,<icon qual>,<icon>"
  if (!ParseUInt(szRsp, FALSE, nDetails, szRsp)         ||
      !ParseRspParamSeparator(szRsp, szRsp)             ||
      !ParseString(szRsp, pText, MAX_ATCMD_LEN, szRsp)  ||
      !ParseRspParamSeparator(szRsp, szRsp)             ||
      !ParseUInt(szRsp, FALSE, nIconQualifier, szRsp)   ||
      !ParseRspParamSeparator(szRsp, szRsp)             ||
      !ParseUInt(szRsp, FALSE, nIcon, szRsp)            ||
      !ParseRspPostfix(szRsp, szRsp)) {
    return FALSE;
  }

  UpdateAlphaField(szText, fUseGSM);

  // Fill out the SAT command
  sprintf(m_szCmdBuffer, "D00081030112%0.2X82028183%s0A01801E02%0.2X%0.2X", nDetails, szText, nIconQualifier, nIcon);

  if (!AddSATCmdLength(m_szCmdBuffer)) {
    if (fUseGSM) { return FALSE; }
    return ParseSendUSSD(szRspIn, pBlob, cbBlob, TRUE);
  }

  // Notify the SIM manager of the SAT command
  return HandleBlob(RIL_NOTIFY_SIMTOOLKITCMD, pBlob, cbBlob, m_szCmdBuffer);
}

//////////////////////////////////////////////////////////////////////////////
//
// Internal parsing function.
//
// Return:
//  TRUE or FALSE depending on the success of the operation.
//
//////////////////////////////////////////////////////////////////////////////
BOOL CSimToolkitHandling::ParseSendSMS(LPCSTR szRspIn, void*& pBlob, UINT& cbBlob, BOOL fUseGSM) {
UINT    nDetails;
UINT    nIconQualifier, nIconId;
char*   pText;
char    szText[MAX_ATCMD_LEN];
LPCSTR  szRsp = szRspIn;

  // Prepare text field
  SIMTK_PREPARE_TEXT(szText, pText, SIMTK_TXT_ALPHA);

  // Parse "<details>"
  if (!ParseUInt(szRsp, FALSE, nDetails, szRsp)         ||
      !ParseRspParamSeparator(szRsp, szRsp)             ||
      !ParseString(szRsp, pText, MAX_ATCMD_LEN, szRsp)  ||
      !ParseRspParamSeparator(szRsp, szRsp)             ||
      !ParseUInt(szRsp, FALSE, nIconQualifier, szRsp)   ||
      !ParseRspParamSeparator(szRsp, szRsp)             ||
      !ParseUInt(szRsp, FALSE, nIconId, szRsp)          ||
      !ParseRspPostfix(szRsp, szRsp)) {
    return FALSE;
  }

  UpdateAlphaField(szText, fUseGSM);

  // Fill out the SAT command details and device ids
  sprintf(m_szCmdBuffer, "D00081030113%0.2X82028183%s0B001E02%0.2X%0.2X", nDetails, szText, nIconQualifier, nIconId);

  if (!AddSATCmdLength(m_szCmdBuffer)) {
    if (fUseGSM) { return FALSE; }
    return ParseSendSMS(szRspIn, pBlob, cbBlob, TRUE);
  }

  // Notify the SIM manager of the SAT command
  return HandleBlob(RIL_NOTIFY_SIMTOOLKITCMD, pBlob, cbBlob, m_szCmdBuffer);
}

//////////////////////////////////////////////////////////////////////////////
//
// Internal parsing function.
//
// Return:
//  TRUE or FALSE depending on the success of the operation.
//
//////////////////////////////////////////////////////////////////////////////
BOOL CSimToolkitHandling::ParsePlayTone(LPCSTR szRspIn, void*& pBlob, UINT& cbBlob, BOOL fUseGSM) {
UINT    nDetails;
UINT    nTone, nDurationUnit, nDuration, nIconQualifier, nIconId;
char*   pText;
char    szText[MAX_ATCMD_LEN];
LPCSTR  szRsp = szRspIn;

  // Prepare text field
  SIMTK_PREPARE_TEXT(szText, pText, SIMTK_TXT_ALPHA);

  // Parse "<details>"
  if (!ParseUInt(szRsp, FALSE, nDetails, szRsp)         ||
      !ParseRspParamSeparator(szRsp, szRsp)             ||
      !ParseString(szRsp, pText, MAX_ATCMD_LEN, szRsp)  ||
      !ParseRspParamSeparator(szRsp, szRsp)             ||
      !ParseUInt(szRsp, FALSE, nTone, szRsp)            ||
      !ParseRspParamSeparator(szRsp, szRsp)             ||
      !ParseUInt(szRsp, FALSE, nDurationUnit, szRsp)    ||
      !ParseRspParamSeparator(szRsp, szRsp)             ||
      !ParseUInt(szRsp, FALSE, nDuration, szRsp)        ||
      !ParseRspParamSeparator(szRsp, szRsp)             ||
      !ParseUInt(szRsp, FALSE, nIconQualifier, szRsp)   ||
      !ParseRspParamSeparator(szRsp, szRsp)             ||
      !ParseUInt(szRsp, FALSE, nIconId, szRsp)          ||
      !ParseRspPostfix(szRsp, szRsp)) {
    return FALSE;
  }

  UpdateAlphaField(szText, fUseGSM);

  // Fill out the SAT command details and device ids
  sprintf(m_szCmdBuffer, "D00081030120%0.2X82028103%s0E01%0.2X0402%0.2X%0.2X1E02%0.2X%0.2X", nDetails, szText, nTone, nDurationUnit, nDuration, nIconQualifier, nIconId);

  if (!AddSATCmdLength(m_szCmdBuffer)) {
    if (fUseGSM) { return FALSE; }
    return ParsePlayTone(szRspIn, pBlob, cbBlob, TRUE);
  }

  // Notify the SIM manager of the SAT command
  return HandleBlob(RIL_NOTIFY_SIMTOOLKITCMD, pBlob, cbBlob, m_szCmdBuffer);
}

//////////////////////////////////////////////////////////////////////////////
//
// Internal parsing function.
//
// Return:
//  TRUE or FALSE depending on the success of the operation.
//
//////////////////////////////////////////////////////////////////////////////
BOOL CSimToolkitHandling::ParseDisplayText(LPCSTR szRspIn, void*& pBlob, UINT& cbBlob, BOOL fUseGSM) {
UINT    nDetails;
UINT    nImmediateResp, nIconQualifier, nIconId;
char*   pText;
char    szText[MAX_ATCMD_LEN];
LPCSTR  szRsp = szRspIn;

  // Prepare text field
  SIMTK_PREPARE_TEXT(szText, pText, SIMTK_TXT_STANDARD);

  // Parse "<details>"
  if (!ParseUInt(szRsp, FALSE, nDetails, szRsp)         ||
      !ParseRspParamSeparator(szRsp, szRsp)             ||
      !ParseString(szRsp, pText, MAX_ATCMD_LEN, szRsp)  ||
      !ParseRspParamSeparator(szRsp, szRsp)             ||
      !ParseUInt(szRsp, FALSE, nImmediateResp, szRsp)   ||
      !ParseRspParamSeparator(szRsp, szRsp)             ||
      !ParseUInt(szRsp, FALSE, nIconQualifier, szRsp)   ||
      !ParseRspParamSeparator(szRsp, szRsp)             ||
      !ParseUInt(szRsp, FALSE, nIconId, szRsp)          ||
      !ParseRspPostfix(szRsp, szRsp)) {
    return FALSE;
  }

  UpdateTextField(szText, fUseGSM);

  // Fill out the SAT command details and device ids
  sprintf(m_szCmdBuffer, "D00081030121%0.2X82028102%s1E02%0.2X%0.2X", nDetails, szText, nIconQualifier, nIconId);
  if(nImmediateResp) {
    // Add out the immediate response
    strcat(m_szCmdBuffer, "2B00");
  }

  if (!AddSATCmdLength(m_szCmdBuffer)) {
    if (fUseGSM) { return FALSE; }
    return ParseDisplayText(szRspIn, pBlob, cbBlob, TRUE);
  }

  // Notify the SIM manager of the SAT command
  return HandleBlob(RIL_NOTIFY_SIMTOOLKITCMD, pBlob, cbBlob, m_szCmdBuffer);
}

//////////////////////////////////////////////////////////////////////////////
//
// Internal parsing function.
//
// Return:
//  TRUE or FALSE depending on the success of the operation.
//
//////////////////////////////////////////////////////////////////////////////
BOOL CSimToolkitHandling::ParseGetInkey(LPCSTR szRspIn, void*& pBlob, UINT& cbBlob, BOOL fUseGSM) {
UINT    nDetails;
UINT    nIconQualifier, nIconId;
char*   pText;
char    szText[MAX_ATCMD_LEN];
LPCSTR  szRsp = szRspIn;

  // Prepare text field
  SIMTK_PREPARE_TEXT(szText, pText, SIMTK_TXT_STANDARD);

  // Parse "<details>"
  if (!ParseUInt(szRsp, FALSE, nDetails, szRsp)         ||
      !ParseRspParamSeparator(szRsp, szRsp)             ||
      !ParseString(szRsp, pText, MAX_ATCMD_LEN, szRsp)  ||
      !ParseRspParamSeparator(szRsp, szRsp)             ||
      !ParseUInt(szRsp, FALSE, nIconQualifier, szRsp)   ||
      !ParseRspParamSeparator(szRsp, szRsp)             ||
      !ParseUInt(szRsp, FALSE, nIconId, szRsp)          ||
      !ParseRspPostfix(szRsp, szRsp)) {
    return FALSE;
  }

  UpdateTextField(szText, fUseGSM);

  // Fill out the SAT command details and device ids
  sprintf(m_szCmdBuffer, "D00081030122%0.2X82028182%s1E02%0.2X%0.2X", nDetails, szText, nIconQualifier, nIconId);

  if (!AddSATCmdLength(m_szCmdBuffer)) {
    if (fUseGSM) { return FALSE; }
    return ParseGetInkey(szRspIn, pBlob, cbBlob, TRUE);
  }

  // Notify the SIM manager of the SAT command
  return HandleBlob(RIL_NOTIFY_SIMTOOLKITCMD, pBlob, cbBlob, m_szCmdBuffer);
}

//////////////////////////////////////////////////////////////////////////////
//
// Internal parsing function.
//
// Return:
//  TRUE or FALSE depending on the success of the operation.
//
//////////////////////////////////////////////////////////////////////////////
BOOL CSimToolkitHandling::ParseGetInput(LPCSTR szRspIn, void*& pBlob, UINT& cbBlob, BOOL fUseGSM) {
UINT    nDetails;
UINT    nResponseMin, nResponseMax, nIconQualifier, nIconId;
char*   pText;
char*   pDefaultText;
char    szText[MAX_ATCMD_LEN], szDefaultText[MAX_ATCMD_LEN];
LPCSTR  szRsp = szRspIn;

  // Prepare text fields
  SIMTK_PREPARE_TEXT(szText, pText, SIMTK_TXT_STANDARD);
  SIMTK_PREPARE_TEXT(szDefaultText, pDefaultText, SIMTK_TXT_DEFAULT);

  // Parse "<details>"
  if (!ParseUInt(szRsp, FALSE, nDetails, szRsp)                ||
      !ParseRspParamSeparator(szRsp, szRsp)                    ||
      !ParseString(szRsp, pText, MAX_ATCMD_LEN, szRsp)         ||
      !ParseRspParamSeparator(szRsp, szRsp)                    ||
      !ParseUInt(szRsp, FALSE, nResponseMin, szRsp)            ||
      !ParseRspParamSeparator(szRsp, szRsp)                    ||
      !ParseUInt(szRsp, FALSE, nResponseMax, szRsp)            ||
      !ParseRspParamSeparator(szRsp, szRsp)                    ||
      !ParseString(szRsp, pDefaultText, MAX_ATCMD_LEN, szRsp)  ||
      !ParseRspParamSeparator(szRsp, szRsp)                    ||
      !ParseUInt(szRsp, FALSE, nIconQualifier, szRsp)          ||
      !ParseRspParamSeparator(szRsp, szRsp)                    ||
      !ParseUInt(szRsp, FALSE, nIconId, szRsp)                 ||
      !ParseRspPostfix(szRsp, szRsp)) {
    return FALSE;
  }

  UpdateTextField(szText, fUseGSM);
  UpdateTextField(szDefaultText, fUseGSM);

  // Fill out the SAT command details
  sprintf(m_szCmdBuffer, "D00081030123%0.2X82028182%s1102%0.2X%0.2X%s1E02%0.2X%0.2X", nDetails, szText, nResponseMin, nResponseMax, szDefaultText, nIconQualifier, nIconId);

  if (!AddSATCmdLength(m_szCmdBuffer)) {
    if (fUseGSM) { return FALSE; }
    return ParseGetInput(szRspIn, pBlob, cbBlob, TRUE);
  }

  // Notify the SIM manager of the SAT command
  return HandleBlob(RIL_NOTIFY_SIMTOOLKITCMD, pBlob, cbBlob, m_szCmdBuffer);
}

//////////////////////////////////////////////////////////////////////////////
//
// Internal parsing function.
//
// Return:
//  TRUE or FALSE depending on the success of the operation.
//
//////////////////////////////////////////////////////////////////////////////
BOOL CSimToolkitHandling::ParseSelectItem(LPCSTR szRspIn, void*& pBlob, UINT& cbBlob, BOOL fUseGSM) {
UINT    i, nCmd, nNumItems, nDetails, nItem, nDefaultItemId;
UINT    nItemIconsPresent, nItemIconsQualifier, nTitleIconQualifier, nTitleIconId;
UINT    nNextActionId[64], nIconId[64];
char*   pText;
char    szText[MAX_ATCMD_LEN];
LPCSTR  szRsp = szRspIn;

  // Prepare text field
  SIMTK_PREPARE_TEXT(szText, pText, SIMTK_TXT_ALPHA);

  // Parse "<commandDetails>,<numOfItems>,<titleText>,<defaultItemId>,<itemIconsPresent>,<itemIconsQualifier>,<titleIconQualifier>,<titleIconId><details>,<numitems>,"titletext",<itemiconspresent>,<itemiconqualifier>,<titleiconqualifier>,<titleiconid>"
  if (!ParseUInt(szRsp, FALSE, nDetails, szRsp)             ||
      !ParseRspParamSeparator(szRsp, szRsp)                 ||
      !ParseUInt(szRsp, FALSE, nNumItems, szRsp)            ||
      !ParseRspParamSeparator(szRsp, szRsp)                 ||
      !ParseString(szRsp, pText, MAX_ATCMD_LEN, szRsp)      ||
      !ParseRspParamSeparator(szRsp, szRsp)                 ||
      !ParseUInt(szRsp, FALSE, nDefaultItemId, szRsp)       ||
      !ParseRspParamSeparator(szRsp, szRsp)                 ||
      !ParseUInt(szRsp, FALSE, nItemIconsPresent, szRsp)    ||
      !ParseRspParamSeparator(szRsp, szRsp)                 ||
      !ParseUInt(szRsp, FALSE, nItemIconsQualifier, szRsp)  ||
      !ParseRspParamSeparator(szRsp, szRsp)                 ||
      !ParseUInt(szRsp, FALSE, nTitleIconQualifier, szRsp)  ||
      !ParseRspParamSeparator(szRsp, szRsp)                 ||
      !ParseUInt(szRsp, FALSE, nTitleIconId, szRsp)         ||
      !ParseRspPostfix(szRsp, szRsp)) {
    return FALSE;
  }

  // An item list without items is invalid
  if (!nNumItems) {
    return FALSE;
  }

  UpdateAlphaField(szText, fUseGSM);

  // Fill out the start of the SAT command and the menu title
  sprintf(m_szCmdBuffer, "D00081030124%0.2X82028182%s", nDetails, szText);

  // Parse the menu items
  // Parse "^SSTGI: <cmdtype>,<itemid>,"itemtext",<nextactionid>,<iconid>"
  nNumItems = min(nNumItems, 64);
  for (i = 0; i < nNumItems; i++) {
    // Prepare text field
    SIMTK_PREPARE_TEXT(szText, pText, SIMTK_TXT_ITEM);

    if (!MatchStringBeginning(szRsp, "^SSTGI: ", szRsp)    ||
        !ParseUInt(szRsp, FALSE, nCmd, szRsp)              ||
        !ParseRspParamSeparator(szRsp, szRsp)              ||
        !ParseUInt(szRsp, FALSE, nItem, szRsp)             ||
        !ParseRspParamSeparator(szRsp, szRsp)              ||
        !ParseString(szRsp, pText, MAX_ATCMD_LEN, szRsp)   ||
        !ParseRspParamSeparator(szRsp, szRsp)              ||
        !ParseUInt(szRsp, FALSE, nNextActionId[i], szRsp)  ||
        !ParseRspParamSeparator(szRsp, szRsp)              ||
        !ParseUInt(szRsp, FALSE, nIconId[i], szRsp)        ||
        !ParseRspPostfix(szRsp, szRsp)) {
      return FALSE;
    }

    // Add the menu item
    UpdateItemField(szText, nItem, fUseGSM);
    strcat(m_szCmdBuffer, szText);
  }

  // Add the next action items
  sprintf(szText, "18%0.2X", nNumItems);
  strcat(m_szCmdBuffer, szText);
  for (i = 0; i < nNumItems; i++) {
    sprintf(szText, "%0.2X", nNextActionId[i]);
    strcat(m_szCmdBuffer, szText);
  }

  // Add the default item identifier
  sprintf(szText, "1001%0.2X", nDefaultItemId);
  strcat(m_szCmdBuffer, szText);

  // Add the title icon information
  sprintf(szText, "1E02%0.2X%0.2X", nTitleIconQualifier, nTitleIconId);
  strcat(m_szCmdBuffer, szText);

  // Add the items icon information
  if (nItemIconsPresent) {
    sprintf(szText, "1F%0.2X%0.2X", nNumItems+1, nItemIconsQualifier);
    strcat(m_szCmdBuffer, szText);
    for (i = 0; i < nNumItems; i++) {
      sprintf(szText, "%0.2X", nIconId[i]);
      strcat(m_szCmdBuffer, szText);
    }
  }

  if (!AddSATCmdLength(m_szCmdBuffer)) {
    if (fUseGSM) { return FALSE; }
    return ParseSelectItem(szRspIn, pBlob, cbBlob, TRUE);
  }

  // Notify the SIM manager of the SAT command
  return HandleBlob(RIL_NOTIFY_SIMTOOLKITCMD, pBlob, cbBlob, m_szCmdBuffer);
}

//////////////////////////////////////////////////////////////////////////////
//
// Internal parsing function.
//
// Return:
//  TRUE or FALSE depending on the success of the operation.
//
//////////////////////////////////////////////////////////////////////////////
BOOL CSimToolkitHandling::ParseSetupMenu(LPCSTR szRspIn, void*& pBlob, UINT& cbBlob, BOOL fUseGSM) {
UINT    i, nCmd, nNumItems, nDetails, nItem;
UINT    nItemIconsPresent, nItemIconsQualifier, nTitleIconQualifier, nTitleIconId;
UINT    nNextActionId[64], nIconId[64];
char*   pText;
char    szText[MAX_ATCMD_LEN];
LPCSTR  szRsp = szRspIn;

  // Prepare text field
  SIMTK_PREPARE_TEXT(szText, pText, SIMTK_TXT_ALPHA);

  // Parse "<details>,<numitems>,"titletext",<itemiconspresent>,<itemiconqualifier>,<titleiconqualifier>,<titleiconid>"
  if (!ParseUInt(szRsp, FALSE, nDetails, szRsp)             ||
      !ParseRspParamSeparator(szRsp, szRsp)                 ||
      !ParseUInt(szRsp, FALSE, nNumItems, szRsp)            ||
      !ParseRspParamSeparator(szRsp, szRsp)                 ||
      !ParseString(szRsp, pText, MAX_ATCMD_LEN, szRsp)      ||
      !ParseRspParamSeparator(szRsp, szRsp)                 ||
      !ParseUInt(szRsp, FALSE, nItemIconsPresent, szRsp)    ||
      !ParseRspParamSeparator(szRsp, szRsp)                 ||
      !ParseUInt(szRsp, FALSE, nItemIconsQualifier, szRsp)  ||
      !ParseRspParamSeparator(szRsp, szRsp)                 ||
      !ParseUInt(szRsp, FALSE, nTitleIconQualifier, szRsp)  ||
      !ParseRspParamSeparator(szRsp, szRsp)                 ||
      !ParseUInt(szRsp, FALSE, nTitleIconId, szRsp)         ||
      !ParseRspPostfix(szRsp, szRsp)) {
    return FALSE;
  }

  // An item list without items is invalid
  if (!nNumItems) {
    return FALSE;
  }

  UpdateAlphaField(szText, fUseGSM);

  // Fill out the start of the SAT command and the menu title
  sprintf(m_szCmdBuffer, "D00081030125%0.2X82028182%s", nDetails, szText);

  // Parse the menu items
  // Parse "^SSTGI: <cmdtype>,<itemid>,"itemtext",<nextactionid>,<iconid>"
  nNumItems = min(nNumItems, 64);
  for (i = 0; i < nNumItems; i++) {
    // Prepare text field
    SIMTK_PREPARE_TEXT(szText, pText, SIMTK_TXT_ITEM);

    if (!MatchStringBeginning(szRsp, "^SSTGI: ", szRsp)    ||
        !ParseUInt(szRsp, FALSE, nCmd, szRsp)              ||
        !ParseRspParamSeparator(szRsp, szRsp)              ||
        !ParseUInt(szRsp, FALSE, nItem, szRsp)             ||
        !ParseRspParamSeparator(szRsp, szRsp)              ||
        !ParseString(szRsp, pText, MAX_ATCMD_LEN, szRsp)   ||
        !ParseRspParamSeparator(szRsp, szRsp)              ||
        !ParseUInt(szRsp, FALSE, nNextActionId[i], szRsp)  ||
        !ParseRspParamSeparator(szRsp, szRsp)              ||
        !ParseUInt(szRsp, FALSE, nIconId[i], szRsp)        ||
        !ParseRspPostfix(szRsp, szRsp)) {
      return FALSE;
    }

    // Add the menu item
    UpdateItemField(szText, nItem, fUseGSM);
    strcat(m_szCmdBuffer, szText);
  }

  // Add the next action items
  sprintf(szText, "18%0.2X", nNumItems);
  strcat(m_szCmdBuffer, szText);
  for (i = 0; i < nNumItems; i++) {
    sprintf(szText, "%0.2X", nNextActionId[i]);
    strcat(m_szCmdBuffer, szText);
  }

  // Add the title icon information
  sprintf(szText, "1E02%0.2X%0.2X", nTitleIconQualifier, nTitleIconId);
  strcat(m_szCmdBuffer, szText);

  // Add the items icon information
  if (nItemIconsPresent) {
    sprintf(szText, "1F%0.2X%0.2X", nNumItems+1, nItemIconsQualifier);
    strcat(m_szCmdBuffer, szText);
    for (i = 0; i < nNumItems; i++) {
      sprintf(szText, "%0.2X", nIconId[i]);
      strcat(m_szCmdBuffer, szText);
    }
  }

  if (!AddSATCmdLength(m_szCmdBuffer)) {
    if (fUseGSM) { return FALSE; }
    return ParseSetupMenu(szRspIn, pBlob, cbBlob, TRUE);
  }

  // Notify the SIM manager of the SAT command
  return HandleBlob(RIL_NOTIFY_SIMTOOLKITEVENT, pBlob, cbBlob, m_szCmdBuffer);
}

//////////////////////////////////////////////////////////////////////////////
//
// Internal parsing function.
//
// Return:
//  TRUE or FALSE depending on the success of the operation.
//
//////////////////////////////////////////////////////////////////////////////
BOOL CSimToolkitHandling::ParseIdleText(LPCSTR szRspIn, void*& pBlob, UINT& cbBlob, BOOL fUseGSM) {
UINT    nDetails;
UINT    nIconQualifier, nIconId;
char*   pText;
char    szText[MAX_ATCMD_LEN];
LPCSTR  szRsp = szRspIn;

  // Prepare text field
  SIMTK_PREPARE_TEXT(szText, pText, SIMTK_TXT_STANDARD);

  // Parse "<details>"
  if (!ParseUInt(szRsp, FALSE, nDetails, szRsp)         ||
      !ParseRspParamSeparator(szRsp, szRsp)             ||
      !ParseString(szRsp, pText, MAX_ATCMD_LEN, szRsp)  ||
      !ParseRspParamSeparator(szRsp, szRsp)             ||
      !ParseUInt(szRsp, FALSE, nIconQualifier, szRsp)   ||
      !ParseRspParamSeparator(szRsp, szRsp)             ||
      !ParseUInt(szRsp, FALSE, nIconId, szRsp)          ||
      !ParseRspPostfix(szRsp, szRsp)) {
    return FALSE;
  }

  UpdateTextField(szText, fUseGSM);

  // Fill out the SAT command details and device ids
  sprintf(m_szCmdBuffer, "D00081030128%0.2X82028182%s1E02%0.2X%0.2X", nDetails, szText, nIconQualifier, nIconId);

  if (!AddSATCmdLength(m_szCmdBuffer)) {
    if (fUseGSM) { return FALSE; }
    return ParseIdleText(szRspIn, pBlob, cbBlob, TRUE);
  }

  // Notify the SIM manager of the SAT command
  return HandleBlob(RIL_NOTIFY_SIMTOOLKITEVENT, pBlob, cbBlob, m_szCmdBuffer);
}

//////////////////////////////////////////////////////////////////////////////
//
// Parsing function called to parse the response to a SIM-Toolkit command.
//
// Return:
//  S_OK on successs, E_FAIL otherwise.
//
//////////////////////////////////////////////////////////////////////////////
HRESULT CSimToolkitHandling::ParseGetCommand(LPCSTR szRsp, void*& pBlob, UINT& cbBlob, LPVOID pParam) {
UINT                  nCmd;
CSimToolkitHandling*  pInstance = (CSimToolkitHandling*)pParam;
HRESULT               hr = S_OK;

  pBlob = 0;
  cbBlob = 0;

  if (!pInstance) {
    return E_FAIL;
  }

  pInstance->m_fNoResponse = FALSE;

  // Parse "<prefix>^SSTGI: <cmdtype>"
  if (!ParseRspPrefix(szRsp, szRsp)                    ||
      !MatchStringBeginning(szRsp, "^SSTGI: ", szRsp)  ||
      !ParseUInt(szRsp, FALSE, nCmd, szRsp)            ||
      !ParseRspParamSeparator(szRsp, szRsp)) {
      return E_FAIL;
  }

  RILRetailTrace((TEXT("RilDrv: SimToolkit: ParseGetCommand: %d\r\n"), nCmd));

  EnterCriticalSection(&(pInstance->m_csLockBuffer));

  switch (nCmd) {
    case SIMTK_CMD_REFRESH:
      if (!pInstance->ParseRefresh(szRsp, pBlob, cbBlob)) {
        RILRetailTrace((TEXT("RilDrv: SimToolkit Error - REFRESH command format corrupt\r\n")));
        hr = E_FAIL;
      }
      break;

    case SIMTK_CMD_SETUP_CALL:
      if (!pInstance->ParseSetupCall(szRsp, pBlob, cbBlob)) {
        RILRetailTrace((TEXT("RilDrv: SimToolkit Error - SETUP CALL command format corrupt\r\n")));
        hr = E_FAIL;
      }
      break;

    case SIMTK_CMD_SEND_SS:
      if (!pInstance->ParseSendSS(szRsp, pBlob, cbBlob)) {
        RILRetailTrace((TEXT("RilDrv: SimToolkit Error - SEND SS command format corrupt\r\n")));
        hr = E_FAIL;
      }
      break;

    case SIMTK_CMD_SEND_USSD:
      if (!pInstance->ParseSendUSSD(szRsp, pBlob, cbBlob)) {
        RILRetailTrace((TEXT("RilDrv: SimToolkit Error - SEND USSD command format corrupt\r\n")));
        hr = E_FAIL;
      }
      break;

    case SIMTK_CMD_SEND_SMS:
      if (!pInstance->ParseSendSMS(szRsp, pBlob, cbBlob)) {
        RILRetailTrace((TEXT("RilDrv: SimToolkit Error - SEND SMS command format corrupt\r\n")));
        hr = E_FAIL;
      }
      break;

    case SIMTK_CMD_PLAY_TONE:
      if (!pInstance->ParsePlayTone(szRsp, pBlob, cbBlob)) {
        RILRetailTrace((TEXT("RilDrv: SimToolkit Error - PLAY TONE command format corrupt\r\n")));
        hr = E_FAIL;
      }
      break;

    case SIMTK_CMD_DISPLAY_TEXT:
      if (!pInstance->ParseDisplayText(szRsp, pBlob, cbBlob)) {
        RILRetailTrace((TEXT("RilDrv: SimToolkit - DISPLAY TEXT command format corrupt\r\n")));
        hr = E_FAIL;
      }
      break;

    case SIMTK_CMD_GET_INKEY:
      if (!pInstance->ParseGetInkey(szRsp, pBlob, cbBlob)) {
        RILRetailTrace((TEXT("RilDrv: SimToolkit - GET INKEY command format corrupt\r\n")));
        hr = E_FAIL;
      }
      break;

    case SIMTK_CMD_GET_INPUT:
      if (!pInstance->ParseGetInput(szRsp, pBlob, cbBlob)) {
        RILRetailTrace((TEXT("RilDrv: SimToolkit Error - GET INPUT command format corrupt\r\n")));
        hr = E_FAIL;
      }
      break;

    case SIMTK_CMD_SELECT_ITEM:
      if (!pInstance->ParseSelectItem(szRsp, pBlob, cbBlob)) {
        RILRetailTrace((TEXT("RilDrv: SimToolkit Error - SELECT ITEM command format corrupt\r\n")));
        hr = E_FAIL;
      }
      break;

    case SIMTK_CMD_SETUP_MENU:
      if (!pInstance->ParseSetupMenu(szRsp, pBlob, cbBlob)) {
        RILRetailTrace((TEXT("RilDrv: SimToolkit Error - SETUP MENU command format corrupt\r\n")));
        hr = E_FAIL;
      }
      break;

    case SIMTK_CMD_SETUP_IDLE_TEXT:
      if (!pInstance->ParseIdleText(szRsp, pBlob, cbBlob)) {
        RILRetailTrace((TEXT("RilDrv: SimToolkit Error - SETUP IDLETEXT command format corrupt\r\n")));
        hr = E_FAIL;
      }
      break;

    case SIMTK_CMD_SETUP_EVENTLIST:
    case SIMTK_CMD_SEND_DTMF:
    case SIMTK_CMD_LAUNCH_BROWSER:
    case SIMTK_CMD_GET_ICON_DATA:
      RILRetailTrace((TEXT("RilDrv: SimToolkit Error - Unsupported SAT command: %i\r\n"), nCmd));
      hr = E_FAIL;
      break;

    default:
      RILRetailTrace((TEXT("RilDrv: SimToolkit Error - Unknown SAT command (%i)\r\n"), nCmd));
      hr = E_FAIL;
      break;
  }

  LeaveCriticalSection(&(pInstance->m_csLockBuffer));

  // Check if anything went wrong
  if (FAILED(hr)) {
    // Try to bring the module back into a proper state
    char szCmd[32];
    sprintf(szCmd, "AT^SSTR=%d,32\r", nCmd);
    if (!QueueInternalCmd(COMMAND_PORT, pInstance->m_pRilDevice, szCmd, CMDOPT_NONE, APIID_SENDSIMTOOLKITCMDRESPONSE, 0, SIMTK_CMD_RETRIES, SIMTK_CMD_RETRY_DELAY)) {
      RILRetailTrace((TEXT("RilDrv: SimToolkit Error - Failed to queue cancel cmd (%i)\r\n"), nCmd));
    }
    if (!QueueInternalCmd(COMMAND_PORT, pInstance->m_pRilDevice, "AT^SSTR=254\r", CMDOPT_NONE, APIID_SENDSIMTOOLKITCMDRESPONSE, 0, SIMTK_CMD_RETRIES, SIMTK_CMD_RETRY_DELAY)) {
      RILRetailTrace((TEXT("RilDrv: SimToolkit Error - Failed to queue quit cmd\r\n")));
    }
  }

  return S_OK;
}

//////////////////////////////////////////////////////////////////////////////
//
// Send the response to a Sim-Toolkit event.
//
// Params:
//  pHandle    : Pointer to CRilInstanceHandle to be used for the operation.
//  lpbResponse: The response to send to the module.
//  dwSize     : The soze of the response.
//
// Return:
//  S_OK on successs, E_FAIL otherwise.
//
//////////////////////////////////////////////////////////////////////////////
HRESULT CSimToolkitHandling::SendCmdResponse(CRilInstanceHandle* pHandle, const BYTE* lpbResponse, DWORD dwSize) {
UINT     i, len, uAddLen;
char     szCmd[MAX_ATCMD_LEN], szUCS2[5];
WCHAR    wcUnicode;
char    *pGSM;
WCHAR   *pUCS2;
UCHAR    ucStatus, ucItem;
BOOL     fUCS2;
HRESULT  hr = S_OK;

  // Check if we have to suppress the response
  if (m_fNoResponse) {
    return S_OK;
  }

  // Check if we have an additional length field
  uAddLen = 0;
  if (lpbResponse[2] == 0x81) {
    uAddLen = 1;
  }

  // Check for a result tag
  if (lpbResponse[9 + uAddLen] == 3) {
    ucStatus = lpbResponse[11 + uAddLen];     // Extract the result code
    if (ucStatus < 7) {
      ucStatus = 0;   // The MC45 treats all values below 7 as 0
    }
  } else {
    ucStatus = 0;  // Assume successful for the moment
  }

  // Check the command response type
  switch (lpbResponse[3 + uAddLen]) {
    case SIMTK_CMD_SETUP_CALL:
      RILRetailTrace((TEXT("RilDrv: SimToolkit: SETUP CALL command response\r\n")));
      if (!ucStatus) {
        // The ongoing command is handled by the application -> simply terminate the SAT session
        ucStatus = 16;
      }
      sprintf(szCmd, "AT^SSTR=16,%d\r", ucStatus);
      break;

    case SIMTK_CMD_SELECT_ITEM:
      RILRetailTrace((TEXT("RilDrv: SimToolkit: SELECT ITEM command response\r\n")));
      if (ucStatus == 0) {
        ucItem = lpbResponse[14 + uAddLen];  // Extract the item number
      } else {
        ucItem = 0;
      }
      // Compose the select item response
      sprintf(szCmd, "AT^SSTR=36,%d,%d\r", ucStatus, ucItem);
      break;

    case SIMTK_CMD_GET_INKEY:
    case SIMTK_CMD_GET_INPUT:
      RILRetailTrace((TEXT("RilDrv: SimToolkit: GET INKEY / INPUT command response\r\n")));
      // Compose the Inkey/Input response
      sprintf(szCmd, "AT^SSTR=%d,%d,,\"", lpbResponse[3 + uAddLen], ucStatus);
      // Check if we have an additional length field
      if (lpbResponse[13 + uAddLen] == 0x81) {
        uAddLen++;
      }
      if (ucStatus == 0) {
        // Extract the user input string
        fUCS2 = FALSE;
        len = lpbResponse[13 + uAddLen] - 1;
        pGSM = (char*)(&(lpbResponse[15 + uAddLen]));
        if (lpbResponse[14 + uAddLen] == 8) {
          fUCS2 = TRUE;
          len = len / 2;
          pUCS2 = (WCHAR*)(&(lpbResponse[16 + uAddLen]));
        }
        if (len > 0) {
          for (i = 0; i < len; i++) {
            if (!fUCS2) {
              if (!GSMCharToUnicode(pGSM[i], &wcUnicode)) {
                wcUnicode = '*';
              }
            } else {
              wcUnicode = pUCS2[i];
            }
            sprintf(szUCS2, "%0.4X", wcUnicode);
            strncat(szCmd, szUCS2, max(0, MAX_ATCMD_LEN - strlen(szCmd) - 1));
          }
        } else {
          strncat(szCmd, "\\1b", max(0, MAX_ATCMD_LEN - strlen(szCmd) - 1));
        }
      }
      strncat(szCmd, "\"\r", max(0, MAX_ATCMD_LEN - strlen(szCmd) - 1));
      break;

    case SIMTK_CMD_REFRESH:
    case SIMTK_CMD_SEND_SS:
    case SIMTK_CMD_SEND_USSD:
    case SIMTK_CMD_SEND_SMS:
    case SIMTK_CMD_PLAY_TONE:
    case SIMTK_CMD_DISPLAY_TEXT:
    case SIMTK_CMD_SETUP_MENU:
    case SIMTK_CMD_SETUP_IDLE_TEXT:
      RILRetailTrace((TEXT("RilDrv: SimToolkit: Default command response (%i)\r\n"), lpbResponse[3 + uAddLen]));
      sprintf(szCmd, "AT^SSTR=%d,%d\r", lpbResponse[3 + uAddLen], ucStatus);
      break;

    case SIMTK_CMD_SETUP_EVENTLIST:
    case SIMTK_CMD_LAUNCH_BROWSER:
    case SIMTK_CMD_SEND_DTMF:
    case SIMTK_CMD_GET_ICON_DATA:
      RILRetailTrace((TEXT("RilDrv: SimToolkit Error - Unsupported command response (%i)\r\n"), lpbResponse[3 + uAddLen]));
      return E_FAIL;

    default:
      RILRetailTrace((TEXT("RilDrv: SimToolkit Error - Unknown command response (%i)\r\n"), lpbResponse[3 + uAddLen]));
      return E_FAIL;
  }

  if (!QueueCmdWithRetry(COMMAND_PORT, pHandle, szCmd, CMDOPT_NONE, APIID_SENDSIMTOOLKITCMDRESPONSE, NULL, NULL, hr, SIMTK_CMD_RETRIES, SIMTK_CMD_RETRY_DELAY, ParseRspError, this)) {
    RILRetailTrace((TEXT("RilDrv: SimToolkit Error - unable to put CCommand into the queue\r\n")));
    return E_FAIL;
  }

  return hr;
}

//////////////////////////////////////////////////////////////////////////////
//
// Send a Sim-Toolkit envelope command.
//
// Params:
//  pHandle   : Pointer to CRilInstanceHandle to be used for the operation.
//  lpbCommand: The command to send to the module.
//  dwSize    : The soze of the command.
//
// Return:
//  S_OK on successs, E_FAIL otherwise.
//
//////////////////////////////////////////////////////////////////////////////
HRESULT CSimToolkitHandling::SendEnvelopeCmd(CRilInstanceHandle* pHandle, const BYTE* lpbCommand, DWORD dwSize) {
char     szCmd[MAX_ATCMD_LEN];
UCHAR    ucStatus;
HRESULT  hr = S_OK;

  // Check the envelope command type
  switch (lpbCommand[0]) {
    case SIMTK_EVT_MENU_SELECTION:
      RILRetailTrace((TEXT("RilDrv: SimToolkit: MENU SELECTION command\r\n")));
      // Check for help request
      if ((lpbCommand[2] > 7) && ((lpbCommand[8] == 15) || (lpbCommand[8] == 95))) {
        ucStatus = 19;
      } else {
        ucStatus = 0;
      }
      // Compose the menu selection command
      sprintf(szCmd, "AT^SSTR=211,%d,%d\r", ucStatus, lpbCommand[8]);
      break;

    case SIMTK_EVT_END_SESSION:
      RILRetailTrace((TEXT("RilDrv: SimToolkit: END SESSION command\r\n")));
      // Terminate the current session
      strcpy(szCmd, "AT^SSTR=254\r");
      break;

    default:
      RILRetailTrace((TEXT("RilDrv: SimToolkit Error - unknown envelope command (0x%0.2X)\r\n"), lpbCommand[0]));
      return E_FAIL;
  }

  if (!QueueCmdWithRetry(COMMAND_PORT, pHandle, szCmd, CMDOPT_NONE, APIID_SENDSIMTOOLKITENVELOPECMD, NULL, NULL, hr, SIMTK_CMD_RETRIES, SIMTK_CMD_RETRY_DELAY)) {
    RILRetailTrace((TEXT("RilDrv: SimToolkit Error - unable to put CCommand into the queue\r\n")));
    return E_FAIL;
  }

  return hr;
}

//////////////////////////////////////////////////////////////////////////////
//
// Parsing function called to fill a structure telling our Sim-Toolkit
// capabilities.
//
// Return:
//  S_OK on successs, E_FAIL otherwise.
//
//////////////////////////////////////////////////////////////////////////////
HRESULT CSimToolkitHandling::ParseGetDevCapsNotifications(LPCSTR szRsp, void*& pBlob, UINT& cbBlob, LPVOID pParam) {
RILSIMTOOLKITNOTIFYCAPS*  prstnc;

  pBlob = NULL;
  cbBlob = 0;

  prstnc = (RILSIMTOOLKITNOTIFYCAPS *)AllocBlob(sizeof(RILSIMTOOLKITNOTIFYCAPS));
  if (!prstnc) {
      return E_OUTOFMEMORY;
  }

  memset(prstnc, 0x00, sizeof(RILSIMTOOLKITNOTIFYCAPS));

  prstnc->cbSize               = sizeof(RILSIMTOOLKITNOTIFYCAPS);
  prstnc->dwParams             = RIL_PARAM_SIMTKN_ALL;
  prstnc->dwRefresh            = RIL_SIMTKN_RADIOIMPLEMENTS_NONOTIFICATION;
  prstnc->dwMoreTime           = RIL_SIMTKN_RADIOIMPLEMENTS_NONOTIFICATION;
  prstnc->dwPollInterval       = RIL_SIMTKN_RADIOIMPLEMENTS_NONOTIFICATION;
  prstnc->dwPollingOff         = RIL_SIMTKN_RADIOIMPLEMENTS_NONOTIFICATION;
  prstnc->dwSetUpCall          = RIL_SIMTKN_MEIMPLEMENTS;
  prstnc->dwSendSS             = RIL_SIMTKN_RADIOIMPLEMENTS_NONOTIFICATION;
  prstnc->dwSendUSSD           = RIL_SIMTKN_RADIOIMPLEMENTS_NONOTIFICATION;
  prstnc->dwSendSMS            = RIL_SIMTKN_RADIOIMPLEMENTS_NONOTIFICATION;
  prstnc->dwPlayTone           = RIL_SIMTKN_MEIMPLEMENTS;
  prstnc->dwDisplayText        = RIL_SIMTKN_MEIMPLEMENTS;
  prstnc->dwGetInkey           = RIL_SIMTKN_MEIMPLEMENTS;
  prstnc->dwGetInput           = RIL_SIMTKN_MEIMPLEMENTS;
  prstnc->dwSelectItem         = RIL_SIMTKN_MEIMPLEMENTS;
  prstnc->dwSetupMenu          = RIL_SIMTKN_MEIMPLEMENTS;
  prstnc->dwSetupIdleModeText  = RIL_SIMTKN_MEIMPLEMENTS;
  prstnc->dwLocalInfo          = RIL_SIMTKN_RADIOIMPLEMENTS_NONOTIFICATION;
  prstnc->dwNotifyFlags        = RIL_CAPS_NOTIFY_SIMTOOLKITCMD |
                                 RIL_CAPS_NOTIFY_SIMTOOLKITEVENT;

  pBlob = (void*)prstnc;
  cbBlob = sizeof(RILSIMTOOLKITNOTIFYCAPS);

  return S_OK;
}

//////////////////////////////////////////////////////////////////////////////
//
// Converts a created SAT command Hex string into binary blob format.
//
//////////////////////////////////////////////////////////////////////////////
void CSimToolkitHandling::ConvertSATBlob(char* szSATCmd, BYTE* pBlob) {
UINT  i, j, len;

  len = strlen(szSATCmd) / 2;
  for (i = 0, j = 0; j < len; j++, i += 2) {
    pBlob[j] = SemiByteCharsToByte(szSATCmd[i], szSATCmd[i+1]);
  }
}

//////////////////////////////////////////////////////////////////////////////
//
// Converts a UCS2 string into ASCII format.
//
//////////////////////////////////////////////////////////////////////////////
void CSimToolkitHandling::ConvertSATString(char* lpszSATString) {
UINT  i, j, len, w;
char  c;

  len = strlen(lpszSATString) / 2;
  for (i = 0, j = 0; i < len; i += 2, j += 4) {
    sscanf(&(lpszSATString[j]), "%04X", &w);
    if (!UnicodeCharToGSM((WCHAR)w, &c)) {
      c = '*';
    }
    sprintf(&(lpszSATString[i]), "%0.2X", c);
  }
}

//////////////////////////////////////////////////////////////////////////////
//
// Converts a UCS2 phone number into a BCD coded address.
//
//////////////////////////////////////////////////////////////////////////////
void CSimToolkitHandling::ConvertSATAddress(char* lpszSATString) {
UINT  i, j, len, c;

  len = strlen(lpszSATString);
  for (i = 0, j = 0; i < len; i += 4) {
    sscanf(&(lpszSATString[i]), "%04X", &c);
    switch (c) {
      case '+':
        ADD_DIGIT(lpszSATString, j, '0');
        ADD_DIGIT(lpszSATString, j, '0');
        break;
      case '*':
        ADD_DIGIT(lpszSATString, j, 'A');
        break;
      case '#':
        ADD_DIGIT(lpszSATString, j, 'B');
        break;
      default:
        ADD_DIGIT(lpszSATString, j, SemiByteToChar((char)((c - '0') & 0x0F), FALSE));
        break;
    }
  }
}

//////////////////////////////////////////////////////////////////////////////
//
// Convert the text info of the alpha field to GSM if the string is too long,
// add the length info.
//
// Return:
//  TRUE if the length was valid, FALSE if it was greater than 255.
//
//////////////////////////////////////////////////////////////////////////////
BOOL CSimToolkitHandling::UpdateTextField(char* szSATText, BOOL fUseGSM) {
  if (fUseGSM || ((strlen(szSATText) - SIMTK_TXT_STANDARD_SIZE) > SIMTK_TXT_MAX_SIZE)) {
    // Convert the text field from UCS2 to GSM and update format field
    ConvertSATString(szSATText + SIMTK_TXT_STANDARD_SIZE);
    szSATText[5] = '4';
  }
  return AddSATCmdLength(szSATText);
}

//////////////////////////////////////////////////////////////////////////////
//
// Convert the text info of the alpha field to GSM if the string is too long,
// add the length info.
//
// Return:
//   TRUE if the length was valid, FALSE if it was greater than 255.
//
//////////////////////////////////////////////////////////////////////////////
BOOL CSimToolkitHandling::UpdateAlphaField(char* szSATText, BOOL fUseGSM) {
UINT  i, len;

  len = strlen(szSATText);
  if (fUseGSM || ((len - SIMTK_TXT_ALPHA_SIZE) > SIMTK_TXT_MAX_SIZE)) {
    // We have to remove the UCS2 flag -> shift the string accordingly
    for (i = SIMTK_TXT_ALPHA_SIZE; i <= len; i++) {
      szSATText[i-2] = szSATText[i];
    }
    // Now convert the text field from UCS2 to GSM
    ConvertSATString(szSATText + SIMTK_TXT_ALPHA_SIZE - 2);
  }
  return AddSATCmdLength(szSATText);
}

//////////////////////////////////////////////////////////////////////////////
//
// Add item number, convert the text info of the alpha field to GSM if the
// string is too long, add the length info.
//
// Return:
//  TRUE if the length was valid, FALSE if it was greater than 255.
//
//////////////////////////////////////////////////////////////////////////////
BOOL CSimToolkitHandling::UpdateItemField(char* szSATText, UINT nItem, BOOL fUseGSM) {
UINT  i, len;
char  szBuf[3];

  len = strlen(szSATText);
  sprintf(szBuf, "%0.2X", nItem);
  if (fUseGSM || ((len - SIMTK_TXT_ITEM_SIZE) > SIMTK_TXT_MAX_SIZE)) {
    // We have to remove the UCS2 flag -> shift the string accordingly
    for (i = SIMTK_TXT_ITEM_SIZE; i <= len; i++) {
      szSATText[i-2] = szSATText[i];
    }
    // Now convert the text field from UCS2 to GSM
    ConvertSATString(szSATText + SIMTK_TXT_ITEM_SIZE - 2);
  }

  // Add item number
  szSATText[4] = szBuf[0];
  szSATText[5] = szBuf[1];

  return AddSATCmdLength(szSATText);
}

//////////////////////////////////////////////////////////////////////////////
//
// Add the the correct length field to the given SAT string.
//
// Return:
//  TRUE if the length was valid, FALSE if it was greater than 255.
//
//////////////////////////////////////////////////////////////////////////////
BOOL CSimToolkitHandling::AddSATCmdLength(char* szSATCmd) {
UINT  i, len;
char  szBuf[3];

  len = strlen(szSATCmd);
  if (len > ((2 * 255) + 4)) {
    return FALSE;
  }
  sprintf(szBuf, "%0.2X", ((len - 4) / 2));
  if (len > ((2 * 127) + 4)) {
    // We have to add additional byte to length information
    // First shift the whole string
    for (i = (len + 2); i > 3; i--) {
      szSATCmd[i] = szSATCmd[i-2];
    }
    // Now add the length information
    szSATCmd[2] = '8';
    szSATCmd[3] = '1';
    szSATCmd[4] = szBuf[0];
    szSATCmd[5] = szBuf[1];
  } else {
    // Just add the length information
    szSATCmd[2] = szBuf[0];
    szSATCmd[3] = szBuf[1];
  }
  return TRUE;
}

//////////////////////////////////////////////////////////////////////////////
//
// Create and send the blob corresponding to the Sim-Toolkit command.
//
// Params:
//  dwNotificationCode: The blob notification code
//  pBlob             : The storage for the blob (out)
//  cbBlob            : The size of the blob (out)
//  szCmd             : The SAT command to be sent
//
// Return:
//  TRUE on successs, FALSE otherwise.
//
//////////////////////////////////////////////////////////////////////////////
BOOL CSimToolkitHandling::HandleBlob(DWORD dwNotificationCode, void*& pBlob, UINT& cbBlob, char* szCmd) {
  // Allocate the blob
  cbBlob = strlen(szCmd) / 2;
  pBlob = AllocBlob(cbBlob);
  if (!pBlob) {
    cbBlob = 0;
    return FALSE;
  }

  ConvertSATBlob(szCmd, (BYTE*)pBlob);

  // Trace blob data
  TraceBlob((BYTE*)pBlob, cbBlob);

  // Notify the SIM manager of the SAT command
  return m_pRilDevice->BroadcastRealBlobNotification(dwNotificationCode, pBlob, cbBlob);
}

